/**
 * 监控数据上报器
 * 支持重试、降级和错误恢复
 */

import type {
  BaseMonitorData,
  MonitorConfig,
  CacheItem,
} from '~/types/monitor';
import { ConfigManager } from './config-manager';
import { DataCache } from './data-cache';

export class MonitorReporter {
  private config: MonitorConfig;
  private configManager: ConfigManager;
  private dataCache: DataCache;
  private isOnline: boolean = navigator.onLine;
  private retryQueue: CacheItem[] = [];
  private isReporting: boolean = false;

  constructor() {
    this.configManager = ConfigManager.getInstance();
    this.config = this.configManager.getConfig();
    this.dataCache = new DataCache();

    this.initNetworkListeners();
    this.startReportLoop();
  }

  /**
   * 初始化网络状态监听
   */
  private initNetworkListeners(): void {
    window.addEventListener('online', () => {
      this.isOnline = true;
      console.log('🌐 [监控系统] 网络已连接，开始重试上报');
      this.processRetryQueue();
    });

    window.addEventListener('offline', () => {
      this.isOnline = false;
      console.log('📴 [监控系统] 网络已断开，暂停上报');
    });
  }

  /**
   * 检测是否为爬虫请求
   */
  private isSpiderRequest(): boolean {
    const userAgent = navigator.userAgent.toLowerCase();
    const spiderKeywords = [
      'bot',
      'spider',
      'crawler',
      'scraper',
      'slurp',
      'yahoo',
      'bing',
      'google',
      'baidu',
      'sogou',
      '360spider',
      'yandex',
      'facebook',
      'twitter',
      'linkedin',
      'pinterest',
      'whatsapp',
      'telegram',
    ];

    return spiderKeywords.some(keyword => userAgent.includes(keyword));
  }

  /**
   * 获取日志级别对应的emoji
   */
  private getLogEmoji(level: string): string {
    const emojiMap: Record<string, string> = {
      info: '💡',
      warn: '⚠️',
      error: '❌',
      fatal: '💥',
    };
    return emojiMap[level] || '📊';
  }

  /**
   * 控制台输出监控数据
   */
  private logToConsole(data: BaseMonitorData): void {
    if (!this.config.enableConsoleLog) return;

    const emoji = this.getLogEmoji(data.level);
    console.log(`${emoji} [监控系统-${data.type || '通用'}]`, data);
  }

  /**
   * 为监控数据添加默认信息
   */
  private addDefaultInfo(data: BaseMonitorData): BaseMonitorData {
    return {
      ...data,
      from: data.from || this.config.projectName,
      url: data.url || window.location.href,
      userAgent: data.userAgent || navigator.userAgent,
      timestamp: data.timestamp || Date.now(),
    };
  }

  /**
   * 发送数据到阿里云（支持重试）
   */
  private async sendToAliyun(
    reportUrl: string,
    data: BaseMonitorData
  ): Promise<boolean> {
    return new Promise(resolve => {
      try {
        // 将数据转换为URL参数
        const params: string[] = [];
        for (const key in data) {
          if (data[key] !== undefined && data[key] !== null) {
            const value = String(data[key]);
            const encodedValue =
              value.startsWith('http') || value.startsWith('https')
                ? encodeURIComponent(value)
                : value;
            params.push(`${key}=${encodedValue}`);
          }
        }

        const finalUrl =
          params.length > 0
            ? reportUrl +
              (reportUrl.includes('?') ? '&' : '?') +
              params.join('&')
            : reportUrl;

        // 创建script标签进行数据上报
        const script = document.createElement('script');
        let resolved = false;

        const cleanup = () => {
          if (script.parentNode) {
            script.parentNode.removeChild(script);
          }
        };

        const handleResult = (success: boolean) => {
          if (!resolved) {
            resolved = true;
            cleanup();
            resolve(success);
          }
        };

        // 设置超时
        const timeout = setTimeout(() => {
          handleResult(false);
        }, 10000);

        script.onload = () => {
          clearTimeout(timeout);
          handleResult(true);
        };

        script.onerror = () => {
          clearTimeout(timeout);
          handleResult(false);
        };

        script.src = finalUrl;
        const head = document.getElementsByTagName('head')[0];
        if (head) {
          head.insertBefore(script, head.firstChild);
        } else {
          handleResult(false);
        }
      } catch (error) {
        console.warn('❌ [监控系统] 上报失败:', error);
        resolve(false);
      }
    });
  }

  /**
   * 批量上报数据
   */
  private async reportBatch(items: CacheItem[]): Promise<void> {
    if (!this.isOnline || items.length === 0) {
      return;
    }

    const failedItems: CacheItem[] = [];

    for (const item of items) {
      const success = await this.sendToAliyun(this.config.reportUrl, item.data);

      if (!success) {
        failedItems.push(item);
      }

      // 添加延迟避免请求过于频繁
      if (items.length > 1) {
        await new Promise(resolve => setTimeout(resolve, 100));
      }
    }

    // 重新加入失败的项目到重试队列
    if (failedItems.length > 0) {
      this.dataCache.requeue(failedItems);
    }
  }

  /**
   * 处理重试队列
   */
  private async processRetryQueue(): Promise<void> {
    if (this.retryQueue.length === 0 || !this.isOnline) {
      return;
    }

    const itemsToRetry = this.retryQueue.splice(0, this.config.batchSize);
    await this.reportBatch(itemsToRetry);
  }

  /**
   * 启动上报循环
   */
  private startReportLoop(): void {
    setInterval(async () => {
      if (this.isReporting || !this.isOnline) {
        return;
      }

      this.isReporting = true;

      try {
        // 处理缓存数据
        const cacheItems = this.dataCache.flush();
        if (cacheItems.length > 0) {
          await this.reportBatch(cacheItems);
        }

        // 处理重试队列
        await this.processRetryQueue();

        // 清理过期的错误计数
        this.dataCache.cleanupErrorCounts();
      } catch (error) {
        console.warn('❌ [监控系统] 上报循环异常:', error);
      } finally {
        this.isReporting = false;
      }
    }, this.config.flushInterval);
  }

  /**
   * 上报监控数据
   */
  report(data: BaseMonitorData): void {
    try {
      // 爬虫请求不上报
      if (this.isSpiderRequest()) {
        console.log('🕷️ [监控系统] 检测到爬虫请求，跳过上报');
        return;
      }

      const completeData = this.addDefaultInfo(data);

      // 控制台输出
      this.logToConsole(completeData);

      // 生产环境才上报到服务器
      if (this.config.enableReport && process.env.NODE_ENV === 'production') {
        this.dataCache.add(completeData);
      }
    } catch (error) {
      // 监控系统自身错误不应该影响主业务
      console.warn('❌ [监控系统] 上报数据时发生错误:', error);
    }
  }

  /**
   * 立即上报（用于重要错误）
   */
  async reportImmediately(data: BaseMonitorData): Promise<boolean> {
    try {
      if (this.isSpiderRequest() || !this.config.enableReport) {
        return false;
      }

      const completeData = this.addDefaultInfo(data);
      this.logToConsole(completeData);

      if (process.env.NODE_ENV === 'production' && this.isOnline) {
        return await this.sendToAliyun(this.config.reportUrl, completeData);
      }

      return true;
    } catch (error) {
      console.warn('❌ [监控系统] 立即上报失败:', error);
      return false;
    }
  }

  /**
   * 销毁上报器
   */
  destroy(): void {
    this.dataCache.destroy();
    this.retryQueue = [];
  }
}
